/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/ganesh/PathRenderer.h"

#include "include/gpu/GrRecordingContext.h"
#include "src/core/SkDrawProcs.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrPaint.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/GrUserStencilSettings.h"
#include "src/gpu/ganesh/geometry/GrStyledShape.h"
#ifdef SK_DEBUG
#include "src/gpu/ganesh/SurfaceDrawContext.h"
#endif

namespace skgpu::ganesh {
#ifdef SK_DEBUG
void PathRenderer::StencilPathArgs::validate() const
{
    SkASSERT(fContext);
    SkASSERT(fSurfaceDrawContext);
    SkASSERT(fClipConservativeBounds);
    SkASSERT(fViewMatrix);
    SkASSERT(fShape);
    SkASSERT(fShape->style().isSimpleFill());
    SkPath path;
    fShape->asPath(&path);
    SkASSERT(!path.isInverseFillType());
}
#endif

// ////////////////////////////////////////////////////////////////////////////

PathRenderer::StencilSupport PathRenderer::getStencilSupport(const GrStyledShape &shape) const
{
    SkDEBUGCODE(SkPath path;) SkDEBUGCODE(shape.asPath(&path);) SkASSERT(shape.style().isSimpleFill());
    SkASSERT(!path.isInverseFillType());
    return this->onGetStencilSupport(shape);
}

bool PathRenderer::drawPath(const DrawPathArgs &args)
{
#ifdef SK_DEBUG
    args.validate();
    CanDrawPathArgs canArgs;
    canArgs.fCaps = args.fContext->priv().caps();
    canArgs.fProxy = args.fSurfaceDrawContext->asRenderTargetProxy();
    canArgs.fClipConservativeBounds = args.fClipConservativeBounds;
    canArgs.fViewMatrix = args.fViewMatrix;
    canArgs.fShape = args.fShape;
    canArgs.fPaint = &args.fPaint;
    canArgs.fSurfaceProps = &args.fSurfaceDrawContext->surfaceProps();
    canArgs.fAAType = args.fAAType;
    canArgs.validate();

    canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
    SkASSERT(CanDrawPath::kNo != this->canDrawPath(canArgs));
    if (!args.fUserStencilSettings->isUnused()) {
        SkPath path;
        args.fShape->asPath(&path);
        SkASSERT(args.fShape->style().isSimpleFill());
        SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape));
    }
#endif
    return this->onDrawPath(args);
}

void PathRenderer::GetPathDevBounds(const SkPath &path, SkISize devSize, const SkMatrix &matrix, SkRect *bounds)
{
    if (path.isInverseFillType()) {
        *bounds = SkRect::Make(devSize);
        return;
    }
    *bounds = path.getBounds();
    matrix.mapRect(bounds);
}

void PathRenderer::onStencilPath(const StencilPathArgs &args)
{
    static constexpr GrUserStencilSettings kIncrementStencil(GrUserStencilSettings::StaticInit<0xffff,
        GrUserStencilTest::kAlways, 0xffff, GrUserStencilOp::kReplace, GrUserStencilOp::kReplace, 0xffff>());

    GrPaint paint;
    DrawPathArgs drawArgs{ args.fContext,
        std::move(paint),
        &kIncrementStencil,
        args.fSurfaceDrawContext,
        nullptr, // clip
        args.fClipConservativeBounds,
        args.fViewMatrix,
        args.fShape,
        (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone,
        false };
    this->drawPath(drawArgs);
}
} // namespace skgpu::ganesh
